[Разбор] Полный разбор проекта MyBlog

Введение

Введение

MyBlog – это легковесное асинхронное веб-приложение для ведения личного блога и галереи нейросетевых артов. Построено на базе фреймворка FastAPI. Основная идея проекта – полная автономность. Отсутствие тяжёлых внешних зависимостей (баз данных) и работа через высокоскоростное In-memory кэширование файловой системы. Это сочетает надёжность хранения в плоских файлах (Markdown) с мгновенным откликом интерфейса Это делает проект идеальным для self-hosted развёртывания.

1. Архитектура и серверная логика: main.py

1.1 Инфраструктурные решения

Проект спроектирован с учётом работы за Reverse Proxy (Nginx/Traefik), что делает его максимально гибким для различных сценариев хостинга.

@app.middleware("http")  
async def add_proxy_headers(request: Request, call_next):  
    path_prefix = request.headers.get("X-Forwarded-Prefix")  
    if path_prefix:  
        request.scope["root_path"] = path_prefix  
    return await call_next(request)

1.2 Работа с базой данных (Flat-file DB)

Архитектура проекта исключает SQL. Мы используем Flat-file approach:

Плюсы: Бэкап блога – это просто копирование папки. Нет оверхеда на коннекты к БД. Скорость доступа к списку постов больше не ограничена скоростью дисковой подсистемы.
Минусы: Отсутствие транзакционности, что полностью нивелируется использованием кэша и атомарных операций записи для персонального блога.

1.3 Система авторизации

Реализована через SessionMiddleware на базе зашифрованных Cookies. Функция require_auth выступает барьером для всех деструктивных действий.

1.3.1 Механизм приватных статей (Access Codes)

Внедрена система дискретных кодов доступа для статей с префиксом [P].

1.4 Контент-пайплайн (Markdown)

Сервер использует динамический рендеринг. Проект поддерживает расширенный синтаксис Obsidian:

1.5 Автоматизация путей через Post-processing

html = html.replace('/blog/static/', '/blog/static/')

Механизм автоматически заменяет относительные пути на абсолютные перед отдачей страницы пользователю. Это гарантирует, что медиаконтент будет корректно отображаться вне зависимости от вложенности URL статьи, а запросы к статике будут мгновенно обрабатываться через Nginx (блок /blog/static/), минуя Python-логику. Это обеспечивает «железную» стабильность отображения картинок и видео.

2. Функциональные блоки (Эндпоинты)

2.1 Галерея и Промты

Галерея – это не просто список картинок. Сервер связывает файлы изображений с их текстовыми описаниями (промтами):

2.2 Универсальный медиа-хаб и безопасность загрузки

2.3 Трюки с вёрсткой (Jinja2 Filters)

Внедрён кастомный фильтр insert_zwsp:

templates.env.filters['insert_zwsp'] = insert_zero_width_spaces

Он автоматически вставляет невидимые пробелы в аномально длинные строки (более 20 символов), которые не являются HTML-тегами. Порог был увеличен с 10 до 20 символов в ходе оптимизации, чтобы исключить разрывы обычных русских слов и сохранить корректную работу алгоритмов ёфикации. Это спасает мобильную вёрстку от "разрывов" из-за сверхдлинных ссылок или технических строк, сохраняя при этом целостность естественного языка.

2.3.1 Типографика и ёфикация

Помимо технических манипуляций со строками, проект следует строгому стандарту ёфикации текста. Использование буквы «ё» во всех материалах блога – это не просто прихоть, а часть философии чистоты контента. Корректная обработка спецсимволов и принудительная ёфикация через фильтры Jinja2 делают чтение технических статей более эстетичным и грамотным, что выделяет проект на фоне типичных «быстрых» решений.

2.4 Интеллектуальный мост: Blog Master (Visual Engine)

В экосистему MyBlog интегрирован мощный визуальный конструктор, позволяющий создавать профессиональные обложки и карточки-анонсы в стиле Flexy без использования Photoshop.

[!WARNING] Исключительно для ПК
Конструктор является профессиональным инструментом и доступен только в десктопной версии. В мобильных браузерах доступ намеренно ограничен, так как корректная вёрстка и рендеринг шрифтов требуют строго определённой ширины экрана. Только на ПК рабочая область гарантирует режим Pixel Perfect: когда финальный файл в форматах PNG или WebP в точности соответствует тому, что вы видите на своём мониторе, без нежелательных переносов строк или искажений.


Благодаря интеллектуальному сбросу масштаба перед рендерингом, вы получаете кристально чистое изображение в исходном высоком разрешении, независимо от выбранного формата холста.

3. Обоснование стека

  1. FastAPI: Минималистичен, быстр, асинхронен. Позволяет легко расширять проект.
  2. Uvicorn: ASGI-сервер с расширенными правами доступа к системным ресурсам (LimitNOFILE=65535). Это позволяет приложению бесперебойно обрабатывать сотни одновременных соединений и потоковую передачу видео, исключая ошибки «Too many open files» под высокой нагрузкой.
  3. Markdown: Выбран как стандарт де-факто для написания заметок (идеальная совместимость с Obsidian).
  4. Jinja2: Серверный рендеринг исключает необходимость в сложных фронтенд-фреймворках, сохраняя при этом интерактивность.

4. Итоги и эксплуатация

Архитектурный вывод: Это надёжное монолитное решение «всё в одном», которое превращает простой текстовый архив в современную высокотехнологичную платформу.

2. Клиентская часть: main.html (Главная страница)

2.1 UI/UX и дизайн-система

Дизайн выполнен в стиле Modern Dark Minimalism.
В свежей итерации интерфейс стал более симметричным и сфокусированным. Основные изменения коснулись визуальной иерархии:

2.2 Динамическая генерация категорий (The Tag System)

Одной из ключевых фишек интерфейса является автоматическая трансформация структуры карточек при загрузке страницы. Система на лету считывает метаданные из названий файлов и модифицирует DOM-дерево для каждой статьи.

Техническая реализация:

const match = fullName.match(/^\[(.*?)\]/);
if (match) {
    const catName = match[1];
    categories.add(catName);
    item.dataset.category = catName.toLowerCase();

    // Создание и внедрение графического бейджа
    const badge = document.createElement('div');
    badge.className = 'post-category';
    badge.textContent = catName;

    // Очистка заголовка от технических скобок
    const cleanTitle = fullName.replace(/^\[.*?\]\s*/, '');
    linkSpan.textContent = cleanTitle;
    item.prepend(badge); 
}

Этот подход полностью избавляет от ручного прописывания тегов в базе данных. Система сама строит дерево категорий и формирует облако тегов в верхней части страницы (categoryBox) исключительно на базе реальных префиксов в именах файлов. Плавное переключение между разделами происходит мгновенно на стороне клиента, обеспечивая безупречный UX.

2.2.1 Система приоритетов (Sticky Posts)

В скрипт initCategories интегрирован алгоритм проверки символа !.

[!WARNING] Важно
Символ ! должен стоять самым первым в названии файла (например, ![Soft] Настройка.md), иначе скрипт не распознает его как команду для закрепления.

2.3 Динамическая фильтрация и поиск

Вместо того чтобы нагружать сервер запросами при каждом вводе буквы, поиск реализован на стороне клиента (Client-side Filtering).

  1. Поиск: Работает мгновенно через includes() по атрибутам data-name.
  2. Категории: Переключаются без перезагрузки страницы. Пользователь видит результат сразу.
  3. Счётчик: Элемент #articles-count динамически обновляется, показывая количество найденных записей. Это отличный UX-паттерн.
  4. Интеллектуальная подгрузка (Lazy Rendering): Для обеспечения стабильных 60 FPS при поиске внедрена система постепенного вывода контента. По умолчанию на экран выводится первая сотня совпадений, а доступ к остальному архиву осуществляется через кнопку «Показать ещё». Это исключает «фризы» браузера при работе с тысячами записей, сохраняя при этом полный доступ ко всей базе статей без перезагрузки страницы.

2.4 AJAX-управление (Админ-панель)

Для авторизованных пользователей предусмотрена возможность управления архивом.

2.5 Технические особенности вёрстки


3. Обоснование архитектурных решений фронтенда

  1. No Framework (Vanilla JS): Использование чистого JavaScript \u2014 осознанный выбор. Для такого функционала React или Vue были бы избыточны (overkill), а текущий код весит всего пару килобайт и работает быстрее любого фреймворка.
  2. Jinja2 Hydration: Начальный список статей рендерится сервером, а затем "подхватывается" скриптами для фильтрации. Это сохраняет SEO-показатели (поисковики видят все ссылки) при полной интерактивности.
  3. LocalStorage Bypass: В отличие от предыдущих модулей, здесь данные полностью контролируются сервером, а фронтенд лишь управляет их отображением.

Плюсы:

Минусы:

Полный разбор архитектуры MyBlog: Article View Engine

Этот модуль (article.html) отвечает за рендеринг и интеллектуальное обогащение контента. Основная фишка заключается в Post-processing на стороне клиента. Мы не просто выводим HTML, мы его дорабатываем авторскими скриптами для достижения безупречного UX и полной автономности.

1. Клиентская обработка контента (Smart Post-processing)

1.1 Оживление текстовых ссылок

Стандартный парсер Markdown часто игнорирует простые текстовые URL, не превращая их в кликабельные элементы. Наш скрипт автоматизирует этот процесс: он находит все строки в тексте соответствующие паттерну https://, и оборачивает их в активные HTML-ссылки. Это гарантирует корректную навигацию, даже если автор статьи забыл использовать синтаксис разметки.

const urlRegex = /(?<!["=])(https?:\/\/[^\s<]+)/g;
articleBody.querySelectorAll('p, li, td').forEach(el => {
  el.innerHTML = el.innerHTML.replace(urlRegex, (url) => {
    return `<a href="${url}" target="_blank" rel="noopener noreferrer">${url}</a>`;
  });
});

Инженерная деталь: Используется регулярное выражение с Lookbehind (?<!["=]). Это критически важный предохранитель: он не даёт скрипту испортить уже существующие HTML-теги, где URL находится внутри атрибутов src или href.

1.2 Динамический парсинг заголовка (Title Engine)

Здесь применяется логика автоматических визуальных меток. Если заголовок статьи в Markdown-файле имеет вид ![OS] Настройка Windows, скрипт выполняет три задачи:

  1. Обработка закрепов: Находит символ ! в начале строки и помечает статью как приоритетную, добавляя иконку гвоздика \u1f4cc.
  2. Выделение категорий: Извлекает тег [OS] и преобразует его в эффектный отдельный графический элемент (category-label) над основным названием.
  3. Очистка заголовка: Полностью удаляет технические префиксы (! и []) из текста <h1>.
    В актуальной версии движка обработка H1 была вынесена из общего цикла JavaScript-обработки текстовых блоков. Теперь за его отображение отвечают строгие CSS-правила с приоритетом !important. Это гарантирует режим Pixel Perfect: заголовок всегда остаётся видимым, не "схлопывается" и корректно переносится по словам даже при наличии сложных символов (например, длинного тире), что исключает любые конфликты со скриптами пост-процессинга
    Такой подход позволяет сохранять профессиональную структуру статьи на сайте, оставляя при этом исходные файлы на диске удобными для поиска и чёткой сортировки в редакторе (например, в Obsidian).

[!WARNING] Важно
Порядок символов в названии файла критичен: первым должен идти восклицательный знак, затем категория в скобках, и только потом название. Пример: ![Soft] Твикер.md.

1.3 Система умных спойлеров (Media Spoiler Engine)

2. Работа с кодом и таблицами

2.1 Code Blocks & Copy Engine

Любой блок программного кода автоматически оборачивается в контейнер .code-block, куда динамически инжектируется кнопка копирования.

2.2 Адаптивные таблицы (Responsive Data Tables)**

Таблицы в вебе – это один из самых «капризных» элементов. Если их просто оставить как есть, они напрочь ломают мобильную вёрстку, растягивая страницу по горизонтали так, что пользователю приходится скроллить весь сайт влево-вправо. В MyBlog реализовано изящное гибридное решение:

1. Серверный этап (Генерация)

Расширение tables в библиотеке markdown превращает стандартную Markdown-разметку:

| Заголовок 1 | Заголовок 2 |
|-------------|-------------|
| Текст 1     | Текст 2     |

в чистый HTML-код: теги <table><thead><tbody><tr> (строки) и <td> (ячейки). Сами по себе эти теги не умеют подстраиваться под размер экрана.

2. Фронтенд-этап (Адаптация)

Поскольку таблицы «дубовые» по своей природе, в твоём коде (в модуле article.html) используется специальный JS-скрипт.

Что он делает (алгоритм):

  1. Находит все таблицы, сгенерированные сервером.
  2. Проверяет их ширину и, вместо того чтобы дать им «разорвать» дизайн, оборачивает каждую таблицу в контейнер div.table-wrapper со свойством overflow-x: auto.

Как это выглядит для пользователя:
Вместо того чтобы вся страница начала «болтаться» на экране смартфона, сама статья остаётся стабильной, а внутри неё появляется область с таблицей, которую можно плавно скроллить пальцем. Это классический пример того, как минималистичный бэкенд дополняется умным фронтендом для обеспечения безупречного UX.

3. Дизайн и типографика статьи (Article View Engine)

Модуль рендеринга контента следует философии Modern Dark Minimalism, обеспечивая безупречный UX при чтении сложных технических материалов:

Визуальная иерархия дополнена умными списками: маркеры ul/ol теперь имеют тот же мягкий оттенок #b0bccd, что и основной текст, и вынесены за пределы текстового блока (list-style-position: outside). Это сохраняет строгий ритм чтения и предотвращает визуальное "слипание" перечислений с основным контентом

[!WARNING] Важно
Использование фильтра размытия (blur) на кнопке не только выглядит эффектно, но и решает проблему читаемости текста, который оказывается «под» кнопкой во время скролла.
Технический акцент: Весь визуал реализован на чистом CSS без внешних шрифтовых иконок или тяжёлых UI-китов, что гарантирует мгновенную отрисовку страницы (LCP) даже на слабых устройствах.

3.1 Интеллектуальное оглавление (Smart TOC)

4. Интеграция с нативной системой (Share API)

Этот модуль отвечает за бесшовную передачу данных между веб-приложением и операционной системой пользователя.

4.1 Смарт-нормализация URL

Кнопка Поделиться не просто копирует URL, она выполняет глубокую очистку и интеллектуальное экранирование адреса:

// Декодируем текущий URL, чтобы работать с чистой кириллицей
let currentUrl = decodeURI(window.location.href);

// Принудительно кодируем спецсимволы, критичные для парсеров:
const beautyUrl = currentUrl
  .replace(/!/g, '%21')
  .replace(/\[/g, '%5B')
  .replace(/\]/g, '%5D')
  .replace(/ /g, '%20')
  .replace(/P/g, '%50');

Инженерная деталь: Использование decodeURI позволяет получить «чистую» кириллицу, а ручное переопределение кодирования для символов ![]P и пробелов гарантирует, что системные маркеры блога не будут «съедены» парсерами мессенджеров. Это делает ссылку полностью безопасной для передачи в Telegram, Discord или WhatsApp, сохраняя её валидность и аккуратный внешний вид.

4.2 Portable Article Engine (Экспорт)

Вместо стандартной печати в проект интегрирован механизм сборки автономного HTML-пакета. При нажатии на кнопку «Экспорт» происходит не просто копирование текущего DOM-дерева, а его интеллектуальная «санация»:
- Бинарная инъекция и прогресс: Скрипт асинхронно конвертирует все изображения, аудио и видео в формат Base64. Процесс сопровождается динамическим прогресс-баром (Сборка: X%), что обеспечивает визуальный отклик при работе с объёмными медиа-массивами.
- Интеллектуальная нормализация медиа: В процессе сборки пакета система автоматически декодирует URL-пути, извлекает оригинальные имена файлов (включая кириллицу) и внедряет их в атрибуты title и download. Это подготавливает автономный файл к корректному распознаванию системными загрузчиками ОС.
- Атомарная очистка DOM: Перед генерацией финального Blob-объекта скрипт проводит «санацию» дерева: удаляет интерактивное оглавление (TOC), скрывает служебные кнопки и возвращает блокам кода их первозданный вид (pre), избавляя оффлайн-копию от лишнего «мусора».
Восстановление кода: Тегам pre возвращается их первозданный вид, без внедрённых скриптами статус-баров. Это гарантирует, что экспортированная статья будет содержать безупречный, валидный код, максимально приближённый к исходному Markdown-оригиналу.
- Сохранение приватности при экспорте: Система спойлеров полностью переносима. При экспорте статьи в автономный HTML-файл все атрибуты data-spoiler и соответствующие CSS-правила сохраняются. Это гарантирует, что даже в оффлайн-копии статьи «горячий» контент останется скрытым до осознанного клика пользователя, сохраняя приватность просмотра вне зависимости от наличия связи с сервером.

Результат: Пользователь получает один .html файл, который открывается в любом браузере без интернета и внешних зависимостей. Это превращает блог в инструмент создания переносимой документации, которую можно хранить вечно.

Цифровая сохранность типографики: Важной особенностью экспорта является полная консервация визуального стиля. Автономная копия статьи сохраняет абсолютную верность типографике: все результаты работы серверных фильтров, включая принудительную ёфикацию и невидимые пробелы (ZWSP), бережно переносятся в HTML-пакет. Это гарантирует, что даже через десятилетия оффлайн-копия будет выглядеть именно так, как её задумал автор, без «разрывов» вёрстки на новых устройствах.

4.3 Нативный Медиа-интерфейс

Для сохранения единого визуального кода и высокого быстродействия проект отказывается от тяжёлых кастомных плееров в пользу нативных элементов браузера. Чтобы стандартные компоненты ОС (на Windows, Android или iOS) не выбивались из общего стиля, применена адаптация через CSS-фильтры:

 /* Инверсия цветов с коррекцией тона под тёмную тему */
 audio { filter: invert(90%) hue-rotate(180deg) brightness(1.1); }

Это решение позволяет системным контроллерам выглядеть как органичная часть дизайна Modern Dark Minimalism, сохраняя при этом аппаратную оптимизацию и нативное управление громкостью.
Нативная поддержка именования: Использование атрибута download в связке с Base64-данными позволяет современным браузерам (включая Chrome) идентифицировать контент, предлагая пользователю человекочитаемые имена файлов при попытке сохранения медиа из автономной статьи.
Структурированные плейлисты: Для группировки аудиоматериалов реализована поддержка компактных плейлистов на базе связки <figure> и <figcaption>. Подписи к трекам наследуют общую типографику параграфов, превращая набор плееров в упорядоченную библиотеку. Такой подход гарантирует безупречную работу медиа-контента даже на старых устройствах, где кастомные JS-плееры могли бы вызвать задержки в отрисовке (LCP).

5. Безопасность и управление


Вердикт по модулю Article

Этот шаблон превращает простой текстовый файл в полноценную веб-страницу.
Главный плюс: Весь функционал (копирование кода, бейджи, ссылки) работает автономно и мгновенно.
Минус: Если в статье будет 500 блоков кода, инициализация 500 кнопок копирования может занять доли микросекунды (что на самом деле незаметно, но мы же задроты, верно?).

Полный разбор архитектуры MyBlog: Gallery & Masonry Engine

Галерея предназначена для отображения нейросетевых артов и видео. Основная техническая сложность здесь – работа с контентом разной высоты без создания визуальных дыр в сетке.

1. Masonry Grid: Математика вёрстки

Вместо использования тяжёлых библиотек (типа Isotope или Masonry.js), в проект интегрирован самописный легковесный алгоритм на Vanilla JS.

  1. Динамическое распределение: Система определяет количество колонок исходя из ширины экрана (от 1 до 3). Используется массив colHeights, инициализированный нулями.
  2. Алгоритм кратчайшей колонки: Для каждого элемента вычисляется его позиция: он всегда встаёт в ту колонку, которая в данный момент является самой кратчайшей. Это исключает появление пустых зон (дыр) при разной высоте контента.
  3. GPU-acceleration: Для перемещения карточек используется translate3d вместо изменения top/left. Это задействует аппаратное ускорение видеокарты, обеспечивая плавность 60 FPS при перестроении сетки.
  4. Адаптивная деградация: На экранах менее 700px алгоритм Masonry автоматически отключается (position: relative), переходя в режим классического вертикального потока. Это экономит ресурсы CPU на слабых смартфонах.
  5. Математическая реализация:
const minH = Math.min(...colHeights), idx = colHeights.indexOf(minH);
item.style.transform = `translate3d(${idx * (itemWidth + gap)}px, ${minH}px, 0)`;

Страховка рендеринга:
Поскольку высота карточки неизвестна до загрузки медиа, вызов resizeInstance дублируется трижды: по событию load, через setTimeout(500) и отдельно по событию onloadedmetadata для каждого видео. Это гарантирует, что сетка не «поплывёт» после того, как тяжёлое видео подгрузит свои размеры.

Динамический расчёт контейнера:
В конце расчёта скрипт находит максимальное значение в colHeights и задаёт высоту родителю: gallery.style.height = Math.max(...colHeights) + "px". Без этого шага последующие элементы страницы (например, футер) «наехали» бы на галерею из-за абсолютного позиционирования элементов.

2. Работа с медиа-контентом

2.1 Поддержка видео

Галерея нативно поддерживает формат MP4. Для экономии ресурсов и создания "живого" эффекта превью:

2.2 Умный Лайтбокс (Просмотрщик)

Реализована собственная система полноэкранного предпросмотра. При клике на медиаконтент создаётся оверлей с динамическим размытием заднего плана (backdrop-filter: blur(15px)). Это программно изолирует внимание пользователя на выбранном арте или видео, создавая глубокое погружение и превращая просмотр в полноценный визуальный опыт. Контент внутри лайтбокса адаптивен и ограничен по высоте (92vh), что исключает появление паразитных полос прокрутки и гарантирует корректное отображение на любых типах дисплеев.

Интеллектуальный рендеринг в модальном окне: Скрипт лайтбокса использует прямые ссылки на рабочие медиа-ресурсы и принудительно сбрасывает CSS-фильтры через content.style.filter = "none". Это гарантирует мгновенное отображение чёткого контента, даже если превью в сетке было сильно заблюрено

2.3 Система умных спойлеров (NSFW Spoiler Engine)

В логику рендеринга медиа-карточек интегрирован алгоритм автоматической защиты контента:

Автоматический блюр в Masonry: Сетка Галереи обучена мгновенно распознавать файлы с суффиксом _S в имени (например, art_S.jpg). Такие карточки по умолчанию рендерятся с экстремальным размытием (blur 40px) и снабжаются сервисным бейджем «18+». Это позволяет безопасно смешивать любой контент в одной ленте, сохраняя эстетику и приличие интерфейса.
Интерактивная интрига и Лайтбокс: При наведении курсора на заблюренную плитку эффект размытия мягко снижается до 25px, создавая визуальный отклик. Полное «раскрытие» контента происходит исключительно в полноэкранном лайтбоксе: JS-движок подхватывает чистый источник (src) и программно нейтрализует все фильтры цензуры, демонстрируя оригинал в идеальном качестве.
Бесшовный визуальный код: Использование CSS-фильтров вместо замены исходников позволяет сохранить целостность Masonry-сетки и избежать «прыжков» вёрстки при взаимодействии с контентом. Это гарантирует стабильность позиций элементов даже при экстремальных значениях размытия.

3. Интеграция с данными ИИ (Prompt Management)

Каждая карточка в галерее – это контейнер для метаданных.


4. Дизайн и UX-фишки


5. Плюсы и минусы решения

Плюсы:

  1. Zero Library: Отсутствие внешних JS-зависимостей делает страницу экстремально лёгкой.
  2. GPU acceleration: Плавная перестройка сетки при изменении размера окна браузера.
  3. Flexibility: Галерея одинаково хорошо работает как с горизонтальными, так и с вертикальными артами.

Минусы:

  1. Initial Load: Функция resizeInstance должна ждать полной загрузки изображений, чтобы узнать их высоту (window.onload). На очень медленном интернете сетка может "прыгнуть" во время инициализации. Решается введением фиксированных пропорций для картинок (aspect-ratio), если они известны заранее.

Полный разбор MyBlog: Система доступа и управления контентом

1. Модуль авторизации: login.html

Страница входа выполнена в стиле Cyber-Dark. Здесь нет ничего лишнего, только функционал, защищённый логикой сессий.

1.1 Механизм редиректов (The "Next" Pattern)

Одной из ключевых особенностей является использование переменной next_url.

1.2 Фронтенд-валидация


2. Модули управления контентом (Data Ingestion)

Это высокотехнологичные интерфейсы для взаимодействия с файловой системой сервера через абстракцию FastAPI UploadFile. Основная архитектурная особенность – полная асинхронность и клиентская валидация перед отправкой.

2.1 Универсальный медиа-загрузчик (upload_media)

В отличие от классических галерей, этот модуль спроектирован как гибкий файловый менеджер для медиафайлов.
 - Динамическая адресация: Пользователь может выбрать целевую папку в static/ (например, для иконок проектов или звуковых эффектов) прямо в интерфейсе загрузки. Система автоматически создаст дерево директорий, если оно отсутствует.
Drag-and-Drop и пакетная обработка: Поддерживается одновременная загрузка до 50 файлов с визуальной индикацией прогресса через XHR-события.
Умное превью пути: Скрипт на лету формирует итоговую ссылку на файл (/static/path/file.ext), что позволяет автору мгновенно копировать путь для вставки в Markdown-черновик.

2.1.1 Процессор статей (upload_article)

Валидация расширений: Сервер принимает исключительно файлы .md. При попытке загрузки сторонних форматов система мгновенно отсекает запрос до начала записи на диск, обеспечивая безопасность хранилища.
Автоматизация публикации: После успешной передачи данных система выполняет «мягкий» редирект на главную страницу через 1.5 секунды. Этого времени достаточно для визуального подтверждения статуса «Опубликовано», после чего пользователь сразу видит обновлЁнный список постов.
- Санитарная обработка заголовков: Модуль загрузки оснащён логикой предотвращения дублирования технических символов. Если пользователь вручную добавил ! в название файла и одновременно активировал чекбокс «Закрепить» в интерфейсе, скрипт автоматически очистит имя от лишних знаков и сформирует корректный заголовок. Это исключает появление артефактов вроде !![Soft] и гарантирует стабильную работу парсера категорий.

2.2 Логика очистки имен (Sanitization)

На странице загрузки статей реализована важная проверка:

safe_name = re.sub(r'[^\w\s\-\.\[\]\(\),!«»"\'\u00A0—;?]', '', file.filename).strip()

Это защищает сервер от инъекций в именах файлов. Если файл называется [AI]; rm -rf /; .md, он превратится в безобидный [AI] rm -rf .md.


3. Административные операции (Destructive Actions)

Проект включает в себя функции «ядерного уничтожения» данных для моментальной и безвозвратной очистки всего архива.

  1. delete_all: Эти эндпоинты защищены двойным барьером.
  2. Кнопка на фронте вызывает confirm().
  3. Декоратор require_auth на бэкенде проверяет наличие активной сессии.
  4. Асинхронное удаление: При удалении одной статьи используется fetch, чтобы не обновлять страницу – это современный стандарт (SPA-подобное поведение).
     Полный разбор архитектуры MyBlog: Data Ingestion (Загрузка данных)

Этот раздел посвящён страницам upload_gallery.html и upload_article.html. С точки зрения архитектуры – это порты ввода данных, реализующие паттерн Client-side File Processing перед отправкой на FastAPI.

1. Стек и UX-инженерия

Обе страницы используют единый визуальный код, но разные механизмы валидации в зависимости от типа контента.

1.1 Универсальный Drag-and-Drop

Вместо стандартных и скучных кнопок выбора файлов реализована интерактивная зона – dropzone.

1.2 Асинхронные пайплайны загрузки

Для отправки данных используется асинхронный fetch с объектом FormData.
Инженерный профит: Страница не перезагружается в процессе отправки. Пользователь видит статус ("Загрузка на сервер...", "Успешно!") в реальном времени.


Этот модуль сложнее, так как он работает с бинарными данными (изображения и видео).

2.1 Двойная валидация

Перед отправкой фронтенд выполняет первичную проверку:

  1. По MIME-типу['image/jpeg', 'image/png', 'image/gif', 'video/mp4'].includes(file.type).
  2. По расширению: На случай, если браузер некорректно определил тип файла.

Это экономит трафик: если пользователь случайно выберет .zip архив, он получит ошибку мгновенно, без ожидания ответа от сервера.### 2.2 Обработка результатов
После загрузки сервер возвращает JSON со списком результатов. Скрипт анализирует его:

const successCount = data.results.filter(r => r.status === 'ok').length;

Это позволяет реализовать частичный успех: если из 10 файлов 8 загрузились, а 2 были повреждены, пользователь узнает точное количество.

3. Глубокий разбор: Загрузка Статей (upload_article)

Этот модуль адаптирован под текстовый Workflow (Obsidian/Notepad++).

3.1 Фильтрация формата .md

В отличие от галереи, здесь кнопка "Опубликовать" (#uploadBtn) изначально заблокирована (disabled). Она "оживает" только тогда, когда в массив selectedFiles попадают файлы с расширением .md.

selectedFiles = Array.from(files).filter(f => f.name.toLowerCase().endsWith('.md'));

3.2 Автоматизация редиректа

После успешной публикации статьи пользователь автоматически перенаправляется на главную страницу блога через 1.5 секунды. Этого времени достаточно, чтобы увидеть сообщение об успехе, после чего система сразу показывает обновлённый список постов.

4. Обоснование инфраструктурных решений

  1. No Heavy Dependencies: Весь функционал drag-and-drop написан на чистом JS без библиотек типа Dropzone.js. Это гарантирует отсутствие конфликтов и минимальный размер страницы (~3-5 Кб).
  2. Security by Design:
  3. На фронтенде ограничены типы файлов (accept=".md", accept="image/*").
  4. На бэкенде (как мы помним из разбора main.py) стоит повторная проверка. Это классическая стратегия Defense in Depth (эшелонированная оборона).
  5. Mobile-First: На мобильных устройствах зона dropzone адаптируется по высоте, а кнопки выбора файлов становятся крупнее, чтобы по ним было легко попасть пальцем.

5. Плюсы и минусы загрузчиков

Плюсы:

Минусы:

Модули загрузки превращают статичное хранилище в динамическую платформу. Использование fetch и FormData делает процесс публикации контента почти мгновенным, превращая MyBlog в полноценную CMS (Content Management System) для личного использования.

Полный разбор архитектуры MyBlog: Authentication Gate

Здесь реализован классический паттерн Stateful Auth, где сервер контролирует доступ на основе сессионных кук, а фронтенд обеспечивает удобную точку входа.

1. UX-инженерия и "Mobile First"

Как и во всём проекте, здесь соблюдён строгий стандарт адаптивности.

2. Логика перенаправлений (Next-параметр)Особое внимание уделено сохранению пути пользователя:

<input type="hidden" name="next_url" value="{{ next_url }}">

Техническая ценность: Если вы, будучи неавторизованным, попытаетесь зайти в панель загрузки статьи, система перекинет вас на логин, но запомнит ваш изначальный запрос. После успешного входа FastAPI прочитает это скрытое поле и вернёт вас именно туда, куда вы шли. Это избавляет от лишних кликов и навигации по меню заново.


Общий итог по проекту (The Big Picture)

Мы разобрали MyBlog сверху донизу:

  1. Ядро (FastAPI): Асинхронная мощь и работа с плоскими файлами (Markdown/JSON) вместо тяжёлых БД.
  2. Фронтенд (Vanilla JS + Jinja2): Молниеносная скорость работы, отсутствие лишних зависимостей и библиотек.
  3. Галерея (Masonry Engine): Умная сетка на GPU-ускоренных трансформациях.
  4. Статьи (Markdown Engine): Автоматическая конвертация заметок из Obsidian в живые статьи с копированием кода и адаптивными таблицами.
  5. Админка (Data Ingestion): Удобная загрузка файлов через Drag-and-Drop и безопасная авторизация.